home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-19
/
iritsm3s.zip
/
IRITPRSR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-29
|
29KB
|
923 lines
/*****************************************************************************
* Generic parser for the "Irit" solid modeller. *
* *
* Written by: Gershon Elber Ver 0.2, Sep. 1991 *
*****************************************************************************/
#ifdef __MSDOS__
#include <stdlib.h>
#endif /* __MSDOS__ */
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <setjmp.h>
#include "irit_sm.h"
#include "iritprsr.h"
#define LOAD_COLOR 14 /* Index color 1 by default. */
#define UNGET_STACK_SIZE 5 /* Internal stack size. */
typedef enum { /* List of all possible tokens enumerated. */
TOKEN_NONE,
TOKEN_OPEN_PAREN,
TOKEN_CLOSE_PAREN,
TOKEN_E2,
TOKEN_P2,
TOKEN_E3,
TOKEN_P3,
TOKEN_NUMBER,
TOKEN_STRING,
TOKEN_VECTOR,
TOKEN_MATRIX,
TOKEN_CTLPT,
TOKEN_VERTEX,
TOKEN_POLYGON,
TOKEN_POLYLINE,
TOKEN_POINTLIST,
TOKEN_OBJECT,
TOKEN_COLOR,
TOKEN_RGB,
TOKEN_INTERNAL,
TOKEN_NORMAL,
TOKEN_PLANE,
TOKEN_CURVE,
TOKEN_SURFACE,
TOKEN_OTHER = 100, /* Probably names & numbers. */
TOKEN_EOF = -1
} TokenType;
typedef enum { /* Possible error code during data parsing. */
IP_NO_ERR = 0,
IP_ERR_NUMBER_EXPECTED,
IP_ERR_OPEN_PAREN_EXPECTED,
IP_ERR_CLOSE_PAREN_EXPECTED,
IP_ERR_LIST_COMP_UNDEF,
IP_ERR_UNDEF_EXPR_HEADER,
IP_ERR_PT_TYPE_EXPECTED,
IP_ERR_OBJECT_EMPTY,
IP_ERR_MIXED_TYPES,
IP_STR_NOT_IN_QUOTES,
IP_ERR_OBJECT_EXPECTED,
IP_ERR_CAGD_LIB_ERR,
IP_ERR_STACK_OVERFLOW,
IP_ERR_DEGEN_POLYGON,
IP_WRN_OBJ_NAME_TRUNC = 100
} IritPrsrErrType;
static int IPGlblLineCount = 0; /* Used to locate errors in input file. */
static IritPrsrErrType IPGlblParserError = IP_NO_ERR; /* Last err # found. */
static char IPGlblTokenError[LINE_LEN_LONG]; /* Last token error was found. */
static jmp_buf LclLongJumpBuffer; /* Used in error traping. */
static int GlblToken = 0, /* Used by the parser, to unget token. */
GlblLineCount = 1; /* Used to locate errors in input file. */
static char GlblStringToken[UNGET_STACK_SIZE][LINE_LEN_LONG];/* Unget tokens.*/
static IPObjectStruct *AllSrfs = NULL;
static IPObjectStruct *AllCrvs = NULL;
static IPObjectStruct *AllPolys = NULL;
int IritPrsrPolyListCirc = TRUE;
int IritPrsrWasViewMat = FALSE,
IritPrsrWasPrspMat = FALSE;
MatrixType IritPrsrViewMat = { /* Isometric view, by default. */
{ -0.707107, -0.408248, 0.577350, 0.000000 },
{ 0.707107, -0.408248, 0.577350, 0.000000 },
{ 0.000000, 0.816496, 0.577350, 0.000000 },
{ 0.000000, 0.000000, 0.000000, 1.000000 }
};
MatrixType IritPrsrPrspMat = {
{ 1, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0.1, -0.35 },
{ 0, 0, 0.35, 1.0 }
};
static void UnGetToken(char *StringToken);
static void GetStringToken(FILE *f, char *StringToken);
static TokenType GetToken(FILE *f, char *StringToken);
static void GetVertexAttributes(IPVertexStruct *PVertex, FILE *f);
static void GetPolygonAttributes(IPPolygonStruct *PPolygon, FILE *f);
static void GetObjectAttributes(IPObjectStruct *PObject, FILE *f);
static void GetPointData(FILE *f, IPPolygonStruct *PPolygon);
static void IPUpdatePolyPlane(IPPolygonStruct *PPoly);
static void ParserError(IritPrsrErrType ErrNum, char *Msg);
static void IritPrsrGetAllObjects(FILE *f, IPObjectStruct *PObjParent);
static void GetCloseParenToken(FILE *f);
static void SkipToCloseParenToken(FILE *f);
static void GetNumericToken(FILE *f, RealType *r);
static void IritPrsrGetAuxObject(FILE *f, IPObjectStruct *PObj);
/*****************************************************************************
* Routine to read the data from a given file. *
*****************************************************************************/
IPObjectStruct *IritPrsrGetObjects(FILE *f)
{
IPObjectStruct *PObjs, *PTmp;
AllSrfs = NULL;
AllCrvs = NULL;
AllPolys = NULL;
/* If the following gain control and is non zero - its from error! */
if (setjmp(LclLongJumpBuffer) != 0) {
if (f != NULL) fclose(f);
return NULL;
}
GlblToken = 0; /* Used in UnGetToken token buffer. */
IPGlblParserError = IP_NO_ERR; /* Reset errors. */
GlblLineCount = 1; /* Reset line counter. */
PTmp = IritPrsrNewObjectStruct();
IritPrsrGetAllObjects(f, PTmp);
if (AllCrvs != NULL || AllSrfs != NULL) {
if ((PObjs = IritPrsrProcessFreeForm(AllCrvs, AllSrfs)) != NULL)
{
for (PTmp = PObjs; PTmp -> Pnext != NULL; PTmp = PTmp -> Pnext) {
if (!IP_HAS_OBJ_COLOR(PTmp)) {
PTmp -> Color = LOAD_COLOR;
IP_SET_OBJ_COLOR(PTmp);
}
}
PTmp -> Pnext = AllPolys;
AllPolys = PObjs;
}
}
fclose(f);
return AllPolys;
}
/*****************************************************************************
* Routine to read the geometry data from a given file. Reads "[OBJECT ..." *
* prefixes only and invoke the auxiliary routine. *
* Note objects may be recursively defined. *
*****************************************************************************/
static void IritPrsrGetAllObjects(FILE *f, IPObjectStruct *PObjParent)
{
char StringToken[LINE_LEN_LONG];
TokenType Token;
int WasObjectToken = FALSE,
Quit = FALSE;
IPObjectStruct *PObj;
while (!Quit) {
while ((Token = GetToken(f, StringToken)) != TOKEN_OPEN_PAREN &&
Token != TOKEN_CLOSE_PAREN &&
Token != TOKEN_EOF);
if (Token == TOKEN_CLOSE_PAREN || Token == TOKEN_EOF)
{
if (Token == TOKEN_CLOSE_PAREN)
UnGetToken(StringToken);
Quit = TRUE;
break;
}
switch (GetToken(f, StringToken)) {
case TOKEN_OBJECT:
WasObjectToken = TRUE;
PObj = IritPrsrNewObjectStruct();
/* The following handle optional attributes in record. */
if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
GetObjectAttributes(PObj, f);
else
{
UnGetToken(StringToken);
}
if (!IP_HAS_OBJ_COLOR(PObj)) {
PObj -> Color = LOAD_COLOR;
IP_SET_OBJ_COLOR(PObj);
}
if (GetToken(f, StringToken) == TOKEN_OTHER &&
strcmp(StringToken, "NONE") != 0)
strcpy(PObj -> Name, StringToken);
IritPrsrGetAllObjects(f, PObj);
GetCloseParenToken(f);
if (PObjParent) {
/* This object contains other object - delete it since */
/* we are flattening the structure here. */
free((VoidPtr) PObjParent);
PObjParent = NULL;
}
break;
default:
if (WasObjectToken) {
ParserError(IP_ERR_OBJECT_EXPECTED, StringToken);
}
UnGetToken(StringToken);
UnGetToken("[");
IritPrsrGetAuxObject(f, PObjParent);
Quit = TRUE;
break;
}
}
}
/*****************************************************************************
* Routine to get close paren token from f. *
*****************************************************************************/
static void GetCloseParenToken(FILE *f)
{
char StringToken[LINE_LEN_LONG];
if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
ParserError(IP_ERR_CLOSE_PAREN_EXPECTED, StringToken);
}
/*****************************************************************************
* Routine to get close paren token from f. *
*****************************************************************************/
static void SkipToCloseParenToken(FILE *f)
{
char StringToken[LINE_LEN_LONG];
while (!feof(f) && GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
}
/*****************************************************************************
* Routine to get one numeric token into r. *
*****************************************************************************/
static void GetNumericToken(FILE *f, RealType *r)
{
char StringToken[LINE_LEN_LONG];
GetToken(f, StringToken);
# ifdef DOUBLE
if (sscanf(StringToken, "%lf", r) != 1)
# else
if (sscanf(StringToken, "%f", r) != 1)
# endif /* DOUBLE */
ParserError(IP_ERR_NUMBER_EXPECTED, StringToken);
}
/*****************************************************************************
* Routine to read the content of a single object. Return TRUE if data is *
* useful for this parser, FALSE if data should be purged. *
*****************************************************************************/
static void IritPrsrGetAuxObject(FILE *f, IPObjectStruct *PObj)
{
int i, j, ErrLine;
TokenType Token;
char *ErrStr, StringToken[LINE_LEN_LONG];
IPPolygonStruct *PPolygon;
CagdCrvStruct *PCurve;
CagdSrfStruct *PSurface;
PObj -> Type = IP_OBJ_UNDEF;
while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN) {
switch (Token = GetToken(f, StringToken)) {
case TOKEN_POLYGON:
case TOKEN_POLYLINE:
case TOKEN_POINTLIST:
PPolygon = IritPrsrNewPolygonStruct();
switch (Token) {
case TOKEN_POLYGON:
PPolygon -> Type = IP_POLYGON;
break;
case TOKEN_POLYLINE:
PPolygon -> Type = IP_POLYLINE;
break;
case TOKEN_POINTLIST:
PPolygon -> Type = IP_POINTLIST;
break;
}
/* The following handle the optional attributes in struct. */
if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
GetPolygonAttributes(PPolygon, f);
else
UnGetToken(StringToken);
/* The following handles reading the vertices. */
GetPointData(f, PPolygon);
if (PPolygon -> Type == IP_POLYGON &&
!IP_HAS_POLY_PLANE(PPolygon))
IPUpdatePolyPlane(PPolygon);
PPolygon -> Pnext = PObj -> U.PPolygon;
PObj -> U.PPolygon = PPolygon;
PObj -> Type = IP_OBJ_POLY;
break;
case TOKEN_MATRIX:
if (strcmp(PObj -> Name, "VIEW_MAT") == 0) {
IritPrsrWasViewMat = TRUE;
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
GetNumericToken(f, &IritPrsrViewMat[i][j]);
GetCloseParenToken(f);
}
else if (strcmp(PObj -> Name, "PRSP_MAT") == 0) {
IritPrsrWasPrspMat = TRUE;
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
GetNumericToken(f, &IritPrsrPrspMat[i][j]);
GetCloseParenToken(f);
}
else
SkipToCloseParenToken(f);
break;
case TOKEN_SURFACE:
ErrLine = GlblLineCount;
PSurface = CagdSrfReadFromFile2(f, &ErrStr, &ErrLine);
GlblLineCount = ErrLine;
if (ErrStr != NULL) {
ParserError(IP_ERR_CAGD_LIB_ERR, ErrStr);
break;
}
if (PSurface != NULL) {
PSurface -> Pnext = PObj -> U.PSrfs;
PObj -> U.PSrfs = PSurface;
}
PObj -> Type = IP_OBJ_SURFACE;
break;
case TOKEN_CURVE:
ErrLine = GlblLineCount;
PCurve = CagdCrvReadFromFile2(f, &ErrStr, &ErrLine);
GlblLineCount = ErrLine;
if (ErrStr != NULL) {
ParserError(IP_ERR_CAGD_LIB_ERR, ErrStr);
break;
}
if (PCurve != NULL) {
PCurve -> Pnext = PObj -> U.PCrvs;
PObj -> U.PCrvs = PCurve;
}
PObj -> Type = IP_OBJ_CURVE;
break;
case TOKEN_NUMBER:
case TOKEN_STRING:
case TOKEN_VECTOR:
case TOKEN_CTLPT:
SkipToCloseParenToken(f);
break;
default:
ParserError(IP_ERR_UNDEF_EXPR_HEADER, StringToken);
break;
} /* Of switch. */
} /* Of while. */
switch (Token) {
case TOKEN_POLYGON:
case TOKEN_POLYLINE:
case TOKEN_POINTLIST:
PObj -> Pnext = AllPolys;
AllPolys = PObj;
break;
case TOKEN_SURFACE:
PObj -> Pnext = AllSrfs;
AllSrfs = PObj;
break;
case TOKEN_CURVE:
PObj -> Pnext = AllCrvs;
AllCrvs = PObj;
break;
default:
free((VoidPtr) PObj);
break;
}
UnGetToken(StringToken);
}
/*****************************************************************************
* Routine to unget one token (on stack of UNGET_STACK_SIZE levels!) *
*****************************************************************************/
static void UnGetToken(char *StringToken)
{
if (GlblToken >= UNGET_STACK_SIZE)
ParserError(IP_ERR_STACK_OVERFLOW, "");
strcpy(GlblStringToken[GlblToken], StringToken);
GlblToken++; /* GlblToken exists - Something in it (no overflow check). */
}
/*****************************************************************************
* Routine to get the next token out of the input file f. *
* Returns the next token found, as StringToken. *
* Note: StringToken must be allocated before calling this routine! *
*****************************************************************************/
static void GetStringToken(FILE *f, char *StringToken)
{
int len;
char c, *LocalStringToken;
if (GlblToken) { /* get first the unget token */
GlblToken--;
strcpy(StringToken, GlblStringToken[GlblToken]);
return;
}
/* skip white spaces: */
while ((!feof(f))
&& (((c = getc(f)) == ' ') || (c == '\t') || (c == '\n')))
if (c == '\n') GlblLineCount++; /* Count the lines. */
LocalStringToken = StringToken;
if (c == '[') /* Its a token by itself so return it. */
*LocalStringToken++ = c; /* Copy the token into string. */
else {
if (!feof(f))
do *LocalStringToken++ = c; /* Copy the token into string. */
while ((!feof(f)) &&
((c = getc(f)) != ' ') && (c != '\t') && (c != '\n'));
if (c == '\n') ungetc(c, f); /* Save it to be counted next time. */
}
*LocalStringToken = 0; /* Put eos. */
/* The following handles the spacial case were we have XXXX] - we must */
/* split it into two token XXXX and ], UnGetToken(']') and return XXXX: */
if ((StringToken[len = strlen(StringToken)-1] == ']') && (len > 0)) {
/* Return CloseParan */
UnGetToken(&StringToken[len]); /* Save next token. */
StringToken[len] = 0; /* Set end of string on "]". */
}
}
/*****************************************************************************
* Routine to get the next token out of the input file f as token number. *
* Note: StringToken must be allocated before calling this routine! *
*****************************************************************************/
static TokenType GetToken(FILE *f, char *StringToken)
{
static int IntTokens[] = {
TOKEN_OPEN_PAREN,
TOKEN_CLOSE_PAREN,
TOKEN_VERTEX,
TOKEN_POLYGON,
TOKEN_POLYLINE,
TOKEN_POINTLIST,
TOKEN_OBJECT,
TOKEN_COLOR,
TOKEN_RGB,
TOKEN_INTERNAL,
TOKEN_NORMAL,
TOKEN_PLANE,
TOKEN_CURVE,
TOKEN_SURFACE,
TOKEN_E2,
TOKEN_P2,
TOKEN_E3,
TOKEN_P3,
TOKEN_NUMBER,
TOKEN_STRING,
TOKEN_VECTOR,
TOKEN_MATRIX,
TOKEN_CTLPT,
0
};
static char *StrTokens[] = {
"[",
"]",
"VERTEX",
"POLYGON",
"POLYLINE",
"POINTLIST",
"OBJECT",
"COLOR",
"RGB",
"INTERNAL",
"NORMAL",
"PLANE",
"CURVE",
"SURFACE",
"E2",
"P2",
"E3",
"P3",
"NUMBER",
"STRING",
"VECTOR",
"MATRIX",
"CTLPT",
NULL
};
int i;
GetStringToken(f, StringToken);
if (feof(f)) return TOKEN_EOF;
for (i = 0; StrTokens[i] != NULL; i++)
if (strcmp(StringToken, StrTokens[i]) == 0) return IntTokens[i];
return TOKEN_OTHER; /* Must be number or name. */
}
/*****************************************************************************
* Routine to read from input file f the following [ATTR ...] [ATTR ...]. *
* Note the '[' was allready read. *
*****************************************************************************/
static void GetVertexAttributes(IPVertexStruct *PVertex, FILE *f)
{
int i;
RealType Len;
char StringToken[LINE_LEN_LONG];
do {
switch (GetToken(f, StringToken)) {
case TOKEN_INTERNAL:
GetCloseParenToken(f);
IP_SET_VRTX_INTERNAL(PVertex);
break;
case TOKEN_NORMAL:
/* The following handles reading 3 coord. of vertex normal. */
for (i = 0; i < 3; i++)
GetNumericToken(f, &PVertex -> Normal[i]);
/* Make sure it is normalized. */
Len = PT_LENGTH(PVertex -> Normal);
for (i = 0; i < 3; i++) PVertex -> Normal[i] /= Len;
GetCloseParenToken(f);
IP_SET_VRTX_NORMAL(PVertex);
break;
default: /* Ignore this option! */
SkipToCloseParenToken(f);
break;
}
}
while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
UnGetToken(StringToken);
}
/*****************************************************************************
* Routine to read from input file f the following [ATTR ...] [ATTR ...]. *
* Note the '[' was allready read. *
*****************************************************************************/
static void GetPolygonAttributes(IPPolygonStruct *PPolygon, FILE *f)
{
int i;
RealType Len;
char StringToken[LINE_LEN_LONG];
do {
switch (GetToken(f, StringToken)) {
case TOKEN_PLANE:
/* The following handles reading of 4 coord. of plane eqn.. */
for (i = 0; i < 4; i++)
GetNumericToken(f, &PPolygon -> Plane[i]);
/* Make sure it is normalized. */
Len = PT_LENGTH(PPolygon -> Plane);
for (i = 0; i < 4; i++) PPolygon -> Plane[i] /= Len;
GetCloseParenToken(f);
IP_SET_POLY_PLANE(PPolygon);
break;
default:
SkipToCloseParenToken(f);
break;
}
}
while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
UnGetToken(StringToken);
}
/*****************************************************************************
* Routine to read from input file f the following [ATTR ...] [ATTR ...]. *
* Note the '[' was allready read. *
*****************************************************************************/
static void GetObjectAttributes(IPObjectStruct *PObject, FILE *f)
{
int i, j;
char StringToken[LINE_LEN_LONG];
do {
switch (GetToken(f, StringToken)) {
case TOKEN_RGB:
/* The following handles reading of 3 coord. of rgb. */
for (i = 0; i < 3; i++) {
GetToken(f, StringToken);
if (sscanf(StringToken, "%d", &j) != 1)
ParserError(IP_ERR_NUMBER_EXPECTED, StringToken);
PObject -> RGB[i] = (unsigned char) j;
}
GetCloseParenToken(f);
IP_SET_OBJ_RGB(PObject);
break;
case TOKEN_COLOR:
GetToken(f, StringToken);
if (sscanf(StringToken, "%d", &i) != 1)
ParserError(IP_ERR_NUMBER_EXPECTED, StringToken);
GetCloseParenToken(f);
PObject -> Color = i;
IP_SET_OBJ_COLOR(PObject);
break;
default:
if ((i = PObject -> Attrs.NumStrAttribs) < MAX_NUM_ATTRS)
{
PObject -> Attrs.StrAttrName[i] = strdup(StringToken);
if (GetToken(f, StringToken) == TOKEN_CLOSE_PAREN) {
UnGetToken(StringToken);
PObject -> Attrs.StrAttrData[i] = "";
}
else {
PObject -> Attrs.StrAttrData[i] = strdup(StringToken);
}
PObject -> Attrs.NumStrAttribs++;
}
SkipToCloseParenToken(f);
break;
}
}
while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
if (!IP_HAS_OBJ_COLOR(PObject)) {
PObject -> Color = LOAD_COLOR;
IP_SET_OBJ_COLOR(PObject);
}
UnGetToken(StringToken);
}
/*****************************************************************************
* Routine to read poly* vertex information. *
*****************************************************************************/
static void GetPointData(FILE *f, IPPolygonStruct *PPolygon)
{
int i, j, Length;
char StringToken[LINE_LEN_LONG];
IPVertexStruct *V,
*VTail = NULL;
if (GetToken(f, StringToken) != TOKEN_OTHER ||
sscanf(StringToken, "%d", &Length) != 1)
ParserError(IP_ERR_NUMBER_EXPECTED, StringToken);
for (i = 0; i < Length; i++) {
if (GetToken(f, StringToken) != TOKEN_OPEN_PAREN)
ParserError(IP_ERR_OPEN_PAREN_EXPECTED, StringToken);
V = IritPrsrNewVertexStruct();
/* The following handle the optional attributes in struct. */
if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
GetVertexAttributes(V, f);
else
UnGetToken(StringToken);
for (j = 0; j < 3; j++) /* Read coordinates. */
GetNumericToken(f, &V -> Coord[j]);
GetCloseParenToken(f);
if (!IP_HAS_VRTX_NORMAL(V))
PT_COPY(V -> Normal, PPolygon -> Plane);
if (VTail == NULL)
PPolygon -> PVertex = VTail = V;
else {
VTail -> Pnext = V;
VTail = V;
}
}
if (IritPrsrPolyListCirc && PPolygon -> Type == IP_POLYGON)
VTail -> Pnext = PPolygon -> PVertex;
GetCloseParenToken(f);
}
/*****************************************************************************
* Routine to update the Plane equation of the given polygon by the order *
* of the first 3 vertices of that polygon. *
*****************************************************************************/
static void IPUpdatePolyPlane(IPPolygonStruct *PPoly)
{
int i;
RealType Len, V1[3], V2[3];
IPVertexStruct *V = PPoly -> PVertex;
if (V == NULL || V -> Pnext == NULL || V -> Pnext -> Pnext == NULL)
ParserError(IP_ERR_DEGEN_POLYGON, "");
PT_SUB(V1, V -> Coord, V -> Pnext -> Coord);
V = V -> Pnext;
PT_SUB(V2, V -> Coord, V -> Pnext -> Coord);
PPoly -> Plane[0] = V1[1] * V2[2] - V2[1] * V1[2];
PPoly -> Plane[1] = V1[2] * V2[0] - V2[2] * V1[0];
PPoly -> Plane[2] = V1[0] * V2[1] - V2[0] * V1[1];
PPoly -> Plane[3] = (-DOT_PROD(PPoly -> Plane, PPoly -> PVertex -> Coord));
/* Normalize the plane such that the normal has length of 1: */
Len = PT_LENGTH(PPoly -> Plane);
for (i = 0; i < 4; i++) PPoly -> Plane[i] /= Len;
}
/*****************************************************************************
* Routine to set a string attribute. A string attribute consists of an *
* attribute name (string) and data (also string). *
* If Data = "", the attribute with name Name is been freed. *
* If attribute by the given name already exists, it is replaced. *
*****************************************************************************/
void IritPrsrSetStrAttrib(IPObjectStruct *PObj, char *Name, char *Data)
{
int i;
IPAttributeStruct *Attr = &PObj -> Attrs;
for (i = 0; i < Attr -> NumStrAttribs; i++) {
if (strcmp(Name, Attr -> StrAttrName[i]) == 0) {
/* If Data is an empty string, remove this entry. */
if (strlen(Data) == 0) {
free((VoidPtr) Attr -> StrAttrName[i]);
free((VoidPtr) Attr -> StrAttrData[i]);
for ( ; i < (int) Attr -> NumStrAttribs - 2; i++) {
Attr -> StrAttrName[i] = Attr -> StrAttrName[i + 1];
Attr -> StrAttrData[i] = Attr -> StrAttrData[i + 1];
}
Attr -> NumStrAttribs--;
}
else {
free((VoidPtr) Attr -> StrAttrData[i]);
Attr -> StrAttrData[i] = strdup(Data);
}
return;
}
}
/* O.k. it is a new attribute. */
if (Attr -> NumStrAttribs >= MAX_NUM_ATTRS) {
return;
}
Attr -> StrAttrName[Attr -> NumStrAttribs] = strdup(Name);
Attr -> StrAttrData[Attr -> NumStrAttribs++] = strdup(Data);
}
/*****************************************************************************
* Routine to get a string attribute. A string attribute consists of an *
* attribute name (string) and data (also string). *
* Returns a pointer to data if string name is found, NULL otherwise. *
*****************************************************************************/
char *IritPrsrGetStrAttrib(IPObjectStruct *PObj, char *Name)
{
int i;
IPAttributeStruct *Attr = &PObj -> Attrs;
/* If Name is an empty string - print all attributes. */
if (Name == NULL || strlen(Name) == 0) return NULL;
for (i = 0; i < Attr -> NumStrAttribs; i++)
if (strcmp(Name, Attr -> StrAttrName[i]) == 0)
return Attr -> StrAttrData[i];
return NULL;
}
/*****************************************************************************
* Routine to allocate a new VertexStruct. *
*****************************************************************************/
IPVertexStruct *IritPrsrNewVertexStruct(void)
{
IPVertexStruct *V = (IPVertexStruct *) malloc(sizeof(IPVertexStruct));
V -> Pnext = NULL;
V -> VAux = NULL;
V -> VTags = 0;
return V;
}
/*****************************************************************************
* Routine to allocate a new PolygonStruct. *
*****************************************************************************/
IPPolygonStruct *IritPrsrNewPolygonStruct(void)
{
IPPolygonStruct *P = (IPPolygonStruct *) malloc(sizeof(IPPolygonStruct));
P -> Pnext = NULL;
P -> PVertex = NULL;
P -> PAux = NULL;
P -> PTags = 0;
return P;
}
/*****************************************************************************
* Routine to allocate a new ObjectStruct. *
*****************************************************************************/
IPObjectStruct *IritPrsrNewObjectStruct(void)
{
IPObjectStruct *O = (IPObjectStruct *) malloc(sizeof(IPObjectStruct));
O -> Pnext = NULL;
O -> U.PPolygon = NULL;
O -> OAux = NULL;
O -> Attrs.NumStrAttribs = 0;
O -> OTags = 0;
O -> Name[0] = 0;
O -> Color = LOAD_COLOR;
O -> FFPolylines = O -> FFPolygons = NULL;
return O;
}
/*****************************************************************************
* Routine to print pasring error according to ErrNum and set GlblParserError.*
*****************************************************************************/
static void ParserError(IritPrsrErrType ErrNum, char *Msg)
{
IPGlblLineCount = GlblLineCount;
IPGlblParserError = ErrNum;
strcpy(IPGlblTokenError, Msg); /* Keep the message in safe place... */
longjmp(LclLongJumpBuffer, 1); /* Jump to... */
}
/*****************************************************************************
* Returns TRUE if error happened, FALSE otherwise. *
* If error, then ErrorMsg is updated to point on static str describing it. *
*****************************************************************************/
int IritPrsrParseError(char **ErrorMsg)
{
IritPrsrErrType Temp;
char TempCopy[LINE_LEN_LONG];
if ((Temp = IPGlblParserError) == IP_NO_ERR) return FALSE;
strcpy(TempCopy, IPGlblTokenError);
IPGlblParserError = IP_NO_ERR;
switch (Temp) {
case IP_ERR_NUMBER_EXPECTED:
sprintf(IPGlblTokenError, "Line %d: Numeric data expected - found %s",
IPGlblLineCount, TempCopy);
break;
case IP_ERR_OPEN_PAREN_EXPECTED:
sprintf(IPGlblTokenError, "Line %d: '[' expected - found '%s'",
IPGlblLineCount, TempCopy);
break;
case IP_ERR_CLOSE_PAREN_EXPECTED:
sprintf(IPGlblTokenError, "Line %d: ']' expected - found '%s'",
IPGlblLineCount, TempCopy);
break;
case IP_ERR_LIST_COMP_UNDEF:
sprintf(IPGlblTokenError, "Line %d: Undefined list element - \"%s\"",
IPGlblLineCount, TempCopy);
break;
case IP_ERR_UNDEF_EXPR_HEADER:
sprintf(IPGlblTokenError, "Line %d: Undefined TOKEN - \"%s\"",
IPGlblLineCount, TempCopy);
break;
case IP_ERR_PT_TYPE_EXPECTED:
sprintf(IPGlblTokenError, "Line %d: Point type expected",
IPGlblLineCount);
break;
case IP_ERR_OBJECT_EMPTY:
sprintf(IPGlblTokenError, "Line %d: Empty object found",
IPGlblLineCount);
break;
case IP_ERR_MIXED_TYPES:
sprintf(IPGlblTokenError,
"Line %d: Mixed data types in same object",
IPGlblLineCount);
break;
case IP_STR_NOT_IN_QUOTES:
sprintf(IPGlblTokenError,
"Line %d: String not in quotes (%s)",
IPGlblLineCount, TempCopy);
break;
case IP_ERR_OBJECT_EXPECTED:
sprintf(IPGlblTokenError,
"Line %d: 'OBJECT' expected, found '%s'",
IPGlblLineCount, TempCopy);
break;
case IP_ERR_CAGD_LIB_ERR:
sprintf(IPGlblTokenError, "Line %d: %s",
IPGlblLineCount, TempCopy);
break;
case IP_ERR_STACK_OVERFLOW:
sprintf(IPGlblTokenError, "Line %d: Parser Stack overflow",
IPGlblLineCount);
break;
default:
sprintf(IPGlblTokenError,
"Line %d: Data file parser - undefined error",
IPGlblLineCount);
break;
}
*ErrorMsg = IPGlblTokenError;
return TRUE;
}